package com.eslserver.action.schedule.job;

import java.io.IOException;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import org.apache.http.client.ClientProtocolException;
import org.hibernate.Session;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerMetaData;
import org.quartz.Trigger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.eslserver.action.helper.PushESLHTTPMultipartPost;
import com.eslserver.core.ScheduleTimerInitializer;
import com.eslserver.dao.DAOException;
import com.eslserver.dao.ESLServerDAOFactory;
import com.eslserver.dao.ScheduleDAO;
import com.eslserver.to.Coordinator;
import com.eslserver.to.ESL;
import com.eslserver.to.Image;
import com.eslserver.to.Schedule;
import com.eslserver.util.HibernateUtil;

public class PushScheduleJob implements Job {
	public static final Logger LOG = LoggerFactory
			.getLogger(PushScheduleJob.class);
	private static final int SLEEP_BUFFER_IN_SECONDS = 60;

	@Override
	public void execute(JobExecutionContext context)
			throws JobExecutionException {
		JobDataMap dataMap = context.getJobDetail().getJobDataMap();
		Integer scheduleID = dataMap.getIntValue("scheduleID");

		StringBuffer pushMessage = new StringBuffer();
		Session session = null;
		try {
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			session.beginTransaction();
			ScheduleDAO scheduleDAO = ESLServerDAOFactory.getDAOFactory(
					ESLServerDAOFactory.ESLSERVER_DAOFACTORY).getScheduleDAO();
			Schedule schedule = scheduleDAO.loadSchedule(scheduleID);
			Image eslImage = schedule.getImage();
			ESL esl = schedule.getEsl();
			Coordinator coordinator = esl.getCoordinator();

			Collection<Schedule> allSchedules = esl.getSchedules();

			// calculate sleep time based on next trigger
			long minTimeDiff = 0;
			Date now = new Date();
			for (Schedule nextSchedule : allSchedules) {
				List<? extends Trigger> triggers = ScheduleTimerInitializer
						.getTriggerDetailByJobKey(nextSchedule);
				if (triggers != null && triggers.size() > 0) {
					Trigger trigger = triggers.get(0);
					if (trigger != null && trigger.getNextFireTime() != null) {
						long timeDiff = trigger.getNextFireTime().getTime()
								- now.getTime();
						if (timeDiff > 0
								&& (minTimeDiff > timeDiff || minTimeDiff == 0)) {
							minTimeDiff = timeDiff;
						}
					}
				}
			}

			// if sleep time is < 60 seconds, don't bother sleeping
			int sleepTime = (int) minTimeDiff / 1000 - SLEEP_BUFFER_IN_SECONDS;
			if (sleepTime <= 0) {
				sleepTime = 0;
			}

			// start push job
			LOG.info("Starting push job for " + esl.getName()
					+ " with scheduleID " + schedule.getScheduleID() + ". "
					+ "Pushing to Coordinator " + coordinator.getIpAddress()
					+ ":" + coordinator.getPort() + ". " + "ESL Mac "
					+ esl.getMacAddress());

			LOG.info("Sleeptime is set to " + sleepTime + " seconds");

			PushESLHTTPMultipartPost pushESLHTTPMultipartPost = new PushESLHTTPMultipartPost(
					esl, coordinator, eslImage, sleepTime);
			pushMessage.append(pushESLHTTPMultipartPost.sendHTTPPost());

			Scheduler scheduler = context.getScheduler();
			SchedulerMetaData metaData = scheduler.getMetaData();

			LOG.info("Ended push job for " + esl.getName());

			LOG.info("Executed " + metaData.getNumberOfJobsExecuted()
					+ " jobs.");
		} catch (DAOException e) {
			LOG.error(e.getMessage(), e);
		} catch (ClientProtocolException e) {
			LOG.error(e.getMessage(), e);
		} catch (IOException e) {
			LOG.error(e.getMessage(), e);
		} catch (SchedulerException e) {
			LOG.error(e.getMessage(), e);
		} finally {
			if (session != null) {
				session.close();
			}
		}

		LOG.info(pushMessage.toString());
	}
}
